In this notebook, we work on a dataset from IMDB site to classify movie reviews into “positive” reviews and “negative” reviews, just based on the text content of the reviews.

library(readr)
library(tidyr)
library(tibble)
library(plotly)

The IMDB dataset

The IMDB dataset , a set of 50,000 highly-polarized reviews from the Internet Movie Database. They are split into 25,000 reviews for training and 25,000 reviews for testing, each set consisting in 50% negative and 50% positive reviews. The IMDB dataset comes packaged with Keras. It has already been preprocessed: the reviews (sequences of words) have been turned into sequences of integers, where each integer stands for a specific word in a dictionary.

Loading the dataset

library(keras)
imdb <- dataset_imdb(num_words = 10000)
c(c(train_data, train_labels), c(test_data, test_labels)) %<-% imdb

The argument num_words = 10000 means that we will only keep the top 10,000 most frequently occurring words in the training data. Rare words will be discarded. This allows us to work with vector data of manageable size.

The variables train_data and test_data are lists of reviews, each review being a list of word indices (encoding a sequence of words). train_labels and test_labels are lists of 0s and 1s, where 0 stands for “negative” and 1 stands for “positive”:

train_labels[[1]]
[1] 1

Top 10,000 most frequent words are considered , no word index will exceed 10,000:

max(sapply(train_data, max))
[1] 9999

Data Preparation

vectorize_sequences <- function(sequences, dimension = 10000) {
  # Creating all-zero matrix of shape (len(sequences), dimension)
  results <- matrix(0, nrow = length(sequences), ncol = dimension)
  for (i in 1:length(sequences))
    # Setting specific indices of results[i] to 1s
    results[i, sequences[[i]]] <- 1
  results
}
# vectorize training data
x_train <- vectorize_sequences(train_data)
# vectorize test data
x_test <- vectorize_sequences(test_data)
#vectorize labels
y_train <- as.numeric(train_labels)
y_test <- as.numeric(test_labels)

Data type of sample is now changed to numeric .

str(x_train[1,])
 num [1:10000] 1 1 0 1 1 1 1 1 1 0 ...

Building the Neural network

The choice of network for the first model of three layers is the ‘relu’ activation function layer_dense(units = 16, activation = "relu"). Each dense layer with a relu activation implements the following chain of tensor operations: output = relu(dot(W, input) + b)

Having 16 hidden units means that the weight matrix W will have shape (input_dimension, 16), i.e. the dot product with W will project the input data onto a 16-dimensional representation space (and then we would add the bias vector b and apply the relu operation).

library(keras)
firstmodel_3layer <- keras_model_sequential() %>% 
  layer_dense(units = 16, activation = "relu", input_shape = c(10000)) %>% 
  layer_dense(units = 16, activation = "relu") %>% 
  layer_dense(units = 1, activation = "sigmoid")

Configure the model - optimiser selection

Lastly, we need to pick a loss function and an optimizer. crossentropy is usually the best choice when you are dealing with models that output probabilities and for binary classification probems. Crossentropy is a quantity from the field of Information Theory, that measures the “distance” between probability distributions, or in our case, between the ground-truth distribution and our predictions.

configuring our model with the rmsprop optimizer and the binary_crossentropy loss function.

firstmodel_3layer %>% compile(
  optimizer = "rmsprop",
  loss = "binary_crossentropy",
  metrics = c("accuracy")
)

Validating our approach

In order to monitor during training the accuracy of the model on data that it has never seen before, we will create a “validation set” by setting apart 10,000 samples from the original training data:

val_indices <- 1:10000
x_val <- x_train[val_indices,]
partial_x_train <- x_train[-val_indices,]
y_val <- y_train[val_indices]
partial_y_train <- y_train[-val_indices]

Training our model for 20 epochs (20 iterations over all samples in the x_train and y_train tensors), in mini-batches of 512 samples. At this same time we will monitor loss and accuracy on the 10,000 samples that we set apart. This is done by passing the validation data as the validation_data argument:

firstmodel_3layer %>% compile(
  optimizer = "rmsprop",
  loss = "binary_crossentropy",
  metrics = c("accuracy")
)
history <- firstmodel_3layer %>% fit(
  partial_x_train,
  partial_y_train,
  epochs = 20,
  batch_size = 512,
  validation_data = list(x_val, y_val)
)
Train on 15000 samples, validate on 10000 samples
Epoch 1/20
2019-02-21 06:27:41.729525: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA

  512/15000 [>.............................] - ETA: 12s - loss: 0.6949 - acc: 0.4746
 1536/15000 [==>...........................] - ETA: 4s - loss: 0.6853 - acc: 0.5234 
 3072/15000 [=====>........................] - ETA: 2s - loss: 0.6526 - acc: 0.6322
 4608/15000 [========>.....................] - ETA: 1s - loss: 0.6321 - acc: 0.6554
 6144/15000 [===========>..................] - ETA: 0s - loss: 0.6038 - acc: 0.6961
 7680/15000 [==============>...............] - ETA: 0s - loss: 0.5787 - acc: 0.7266
 9216/15000 [=================>............] - ETA: 0s - loss: 0.5603 - acc: 0.7453
10752/15000 [====================>.........] - ETA: 0s - loss: 0.5456 - acc: 0.7568
12800/15000 [========================>.....] - ETA: 0s - loss: 0.5271 - acc: 0.7703
14336/15000 [===========================>..] - ETA: 0s - loss: 0.5136 - acc: 0.7791
15000/15000 [==============================] - 1s 80us/step - loss: 0.5075 - acc: 0.7833 - val_loss: 0.3810 - val_acc: 0.8669
Epoch 2/20

  512/15000 [>.............................] - ETA: 0s - loss: 0.3238 - acc: 0.8984
 2048/15000 [===>..........................] - ETA: 0s - loss: 0.3304 - acc: 0.9067
 3584/15000 [======>.......................] - ETA: 0s - loss: 0.3188 - acc: 0.9093
 5120/15000 [=========>....................] - ETA: 0s - loss: 0.3096 - acc: 0.9119
 6656/15000 [============>.................] - ETA: 0s - loss: 0.3070 - acc: 0.9093
 8704/15000 [================>.............] - ETA: 0s - loss: 0.3111 - acc: 0.9023
10752/15000 [====================>.........] - ETA: 0s - loss: 0.3074 - acc: 0.9046
12288/15000 [=======================>......] - ETA: 0s - loss: 0.3048 - acc: 0.9031
14336/15000 [===========================>..] - ETA: 0s - loss: 0.3016 - acc: 0.9028
15000/15000 [==============================] - 1s 45us/step - loss: 0.2998 - acc: 0.9036 - val_loss: 0.2996 - val_acc: 0.8905
Epoch 3/20

  512/15000 [>.............................] - ETA: 0s - loss: 0.2107 - acc: 0.9414
 2560/15000 [====>.........................] - ETA: 0s - loss: 0.2188 - acc: 0.9367
 4608/15000 [========>.....................] - ETA: 0s - loss: 0.2205 - acc: 0.9362
 6656/15000 [============>.................] - ETA: 0s - loss: 0.2189 - acc: 0.9354
 8704/15000 [================>.............] - ETA: 0s - loss: 0.2199 - acc: 0.9305
10240/15000 [===================>..........] - ETA: 0s - loss: 0.2192 - acc: 0.9300
11264/15000 [=====================>........] - ETA: 0s - loss: 0.2196 - acc: 0.9293
12800/15000 [========================>.....] - ETA: 0s - loss: 0.2185 - acc: 0.9290
14336/15000 [===========================>..] - ETA: 0s - loss: 0.2168 - acc: 0.9293
15000/15000 [==============================] - 1s 46us/step - loss: 0.2164 - acc: 0.9295 - val_loss: 0.2989 - val_acc: 0.8805
Epoch 4/20

  512/15000 [>.............................] - ETA: 0s - loss: 0.1833 - acc: 0.9395
 2048/15000 [===>..........................] - ETA: 0s - loss: 0.1834 - acc: 0.9468
 3584/15000 [======>.......................] - ETA: 0s - loss: 0.1760 - acc: 0.9481
 5120/15000 [=========>....................] - ETA: 0s - loss: 0.1759 - acc: 0.9475
 6656/15000 [============>.................] - ETA: 0s - loss: 0.1745 - acc: 0.9473
 8192/15000 [===============>..............] - ETA: 0s - loss: 0.1726 - acc: 0.9479
 9728/15000 [==================>...........] - ETA: 0s - loss: 0.1709 - acc: 0.9473
11264/15000 [=====================>........] - ETA: 0s - loss: 0.1731 - acc: 0.9450
12800/15000 [========================>.....] - ETA: 0s - loss: 0.1757 - acc: 0.9430
14848/15000 [============================>.] - ETA: 0s - loss: 0.1742 - acc: 0.9427
15000/15000 [==============================] - 1s 47us/step - loss: 0.1740 - acc: 0.9427 - val_loss: 0.2791 - val_acc: 0.8877
Epoch 5/20

  512/15000 [>.............................] - ETA: 0s - loss: 0.1268 - acc: 0.9668
 2048/15000 [===>..........................] - ETA: 0s - loss: 0.1358 - acc: 0.9644
 3584/15000 [======>.......................] - ETA: 0s - loss: 0.1334 - acc: 0.9651
 5120/15000 [=========>....................] - ETA: 0s - loss: 0.1326 - acc: 0.9631
 6656/15000 [============>.................] - ETA: 0s - loss: 0.1400 - acc: 0.9576
 8192/15000 [===============>..............] - ETA: 0s - loss: 0.1383 - acc: 0.9572
 9728/15000 [==================>...........] - ETA: 0s - loss: 0.1380 - acc: 0.9570
11776/15000 [======================>.......] - ETA: 0s - loss: 0.1398 - acc: 0.9558
13824/15000 [==========================>...] - ETA: 0s - loss: 0.1416 - acc: 0.9538
15000/15000 [==============================] - 1s 44us/step - loss: 0.1416 - acc: 0.9539 - val_loss: 0.2831 - val_acc: 0.8873
Epoch 6/20

  512/15000 [>.............................] - ETA: 0s - loss: 0.1216 - acc: 0.9707
 2048/15000 [===>..........................] - ETA: 0s - loss: 0.1099 - acc: 0.9746
 3584/15000 [======>.......................] - ETA: 0s - loss: 0.1067 - acc: 0.9727
 5120/15000 [=========>....................] - ETA: 0s - loss: 0.1149 - acc: 0.9678
 7168/15000 [=============>................] - ETA: 0s - loss: 0.1145 - acc: 0.9671
 9216/15000 [=================>............] - ETA: 0s - loss: 0.1151 - acc: 0.9652
10752/15000 [====================>.........] - ETA: 0s - loss: 0.1145 - acc: 0.9654
12800/15000 [========================>.....] - ETA: 0s - loss: 0.1144 - acc: 0.9653
14336/15000 [===========================>..] - ETA: 0s - loss: 0.1142 - acc: 0.9654
15000/15000 [==============================] - 1s 49us/step - loss: 0.1143 - acc: 0.9654 - val_loss: 0.3111 - val_acc: 0.8814
Epoch 7/20

  512/15000 [>.............................] - ETA: 0s - loss: 0.1033 - acc: 0.9707
 2048/15000 [===>..........................] - ETA: 0s - loss: 0.0962 - acc: 0.9727
 3584/15000 [======>.......................] - ETA: 0s - loss: 0.0935 - acc: 0.9741
 5120/15000 [=========>....................] - ETA: 0s - loss: 0.0914 - acc: 0.9754
 7168/15000 [=============>................] - ETA: 0s - loss: 0.0939 - acc: 0.9735
 9216/15000 [=================>............] - ETA: 0s - loss: 0.0950 - acc: 0.9730
10752/15000 [====================>.........] - ETA: 0s - loss: 0.0965 - acc: 0.9722
12288/15000 [=======================>......] - ETA: 0s - loss: 0.0966 - acc: 0.9718
14336/15000 [===========================>..] - ETA: 0s - loss: 0.0970 - acc: 0.9715
15000/15000 [==============================] - 1s 44us/step - loss: 0.0971 - acc: 0.9715 - val_loss: 0.3132 - val_acc: 0.8833
Epoch 8/20

  512/15000 [>.............................] - ETA: 0s - loss: 0.0741 - acc: 0.9824
 2048/15000 [===>..........................] - ETA: 0s - loss: 0.0696 - acc: 0.9824
 3584/15000 [======>.......................] - ETA: 0s - loss: 0.0714 - acc: 0.9805
 5632/15000 [==========>...................] - ETA: 0s - loss: 0.0740 - acc: 0.9790
 7680/15000 [==============>...............] - ETA: 0s - loss: 0.0738 - acc: 0.9794
 9728/15000 [==================>...........] - ETA: 0s - loss: 0.0780 - acc: 0.9775
11264/15000 [=====================>........] - ETA: 0s - loss: 0.0795 - acc: 0.9767
12800/15000 [========================>.....] - ETA: 0s - loss: 0.0797 - acc: 0.9765
14848/15000 [============================>.] - ETA: 0s - loss: 0.0796 - acc: 0.9769
15000/15000 [==============================] - 1s 44us/step - loss: 0.0806 - acc: 0.9765 - val_loss: 0.3841 - val_acc: 0.8677
Epoch 9/20

  512/15000 [>.............................] - ETA: 0s - loss: 0.0817 - acc: 0.9766
 2048/15000 [===>..........................] - ETA: 0s - loss: 0.0625 - acc: 0.9844
 4096/15000 [=======>......................] - ETA: 0s - loss: 0.0591 - acc: 0.9871
 5632/15000 [==========>...................] - ETA: 0s - loss: 0.0616 - acc: 0.9853
 7168/15000 [=============>................] - ETA: 0s - loss: 0.0607 - acc: 0.9855
 9216/15000 [=================>............] - ETA: 0s - loss: 0.0627 - acc: 0.9848
10752/15000 [====================>.........] - ETA: 0s - loss: 0.0672 - acc: 0.9821
12800/15000 [========================>.....] - ETA: 0s - loss: 0.0672 - acc: 0.9822
14848/15000 [============================>.] - ETA: 0s - loss: 0.0660 - acc: 0.9824
15000/15000 [==============================] - 1s 43us/step - loss: 0.0663 - acc: 0.9821 - val_loss: 0.3653 - val_acc: 0.8755
Epoch 10/20

  512/15000 [>.............................] - ETA: 0s - loss: 0.0536 - acc: 0.9922
 2048/15000 [===>..........................] - ETA: 0s - loss: 0.0509 - acc: 0.9917
 4096/15000 [=======>......................] - ETA: 0s - loss: 0.0521 - acc: 0.9900
 5632/15000 [==========>...................] - ETA: 0s - loss: 0.0517 - acc: 0.9893
 7168/15000 [=============>................] - ETA: 0s - loss: 0.0511 - acc: 0.9897
 9216/15000 [=================>............] - ETA: 0s - loss: 0.0514 - acc: 0.9889
11264/15000 [=====================>........] - ETA: 0s - loss: 0.0546 - acc: 0.9869
13312/15000 [=========================>....] - ETA: 0s - loss: 0.0561 - acc: 0.9855
14848/15000 [============================>.] - ETA: 0s - loss: 0.0553 - acc: 0.9856
15000/15000 [==============================] - 1s 43us/step - loss: 0.0557 - acc: 0.9853 - val_loss: 0.3847 - val_acc: 0.8774
Epoch 11/20

  512/15000 [>.............................] - ETA: 0s - loss: 0.0406 - acc: 0.9941
 2560/15000 [====>.........................] - ETA: 0s - loss: 0.0364 - acc: 0.9949
 4096/15000 [=======>......................] - ETA: 0s - loss: 0.0347 - acc: 0.9951
 5632/15000 [==========>...................] - ETA: 0s - loss: 0.0362 - acc: 0.9936
 7168/15000 [=============>................] - ETA: 0s - loss: 0.0367 - acc: 0.9934
 9216/15000 [=================>............] - ETA: 0s - loss: 0.0446 - acc: 0.9893
10752/15000 [====================>.........] - ETA: 0s - loss: 0.0444 - acc: 0.9892
12288/15000 [=======================>......] - ETA: 0s - loss: 0.0451 - acc: 0.9887
13824/15000 [==========================>...] - ETA: 0s - loss: 0.0448 - acc: 0.9890
15000/15000 [==============================] - 1s 43us/step - loss: 0.0454 - acc: 0.9886 - val_loss: 0.4164 - val_acc: 0.8760
Epoch 12/20

  512/15000 [>.............................] - ETA: 0s - loss: 0.0291 - acc: 0.9961
 2048/15000 [===>..........................] - ETA: 0s - loss: 0.0273 - acc: 0.9980
 3584/15000 [======>.......................] - ETA: 0s - loss: 0.0280 - acc: 0.9975
 5632/15000 [==========>...................] - ETA: 0s - loss: 0.0318 - acc: 0.9952
 7680/15000 [==============>...............] - ETA: 0s - loss: 0.0316 - acc: 0.9956
 9728/15000 [==================>...........] - ETA: 0s - loss: 0.0320 - acc: 0.9952
11264/15000 [=====================>........] - ETA: 0s - loss: 0.0322 - acc: 0.9949
12800/15000 [========================>.....] - ETA: 0s - loss: 0.0324 - acc: 0.9946
14848/15000 [============================>.] - ETA: 0s - loss: 0.0383 - acc: 0.9914
15000/15000 [==============================] - 1s 43us/step - loss: 0.0384 - acc: 0.9912 - val_loss: 0.4493 - val_acc: 0.8693
Epoch 13/20

  512/15000 [>.............................] - ETA: 0s - loss: 0.0238 - acc: 0.9980
 2048/15000 [===>..........................] - ETA: 0s - loss: 0.0262 - acc: 0.9966
 3584/15000 [======>.......................] - ETA: 0s - loss: 0.0247 - acc: 0.9972
 5632/15000 [==========>...................] - ETA: 0s - loss: 0.0230 - acc: 0.9975
 7680/15000 [==============>...............] - ETA: 0s - loss: 0.0246 - acc: 0.9964
 9216/15000 [=================>............] - ETA: 0s - loss: 0.0248 - acc: 0.9963
11264/15000 [=====================>........] - ETA: 0s - loss: 0.0253 - acc: 0.9966
13312/15000 [=========================>....] - ETA: 0s - loss: 0.0257 - acc: 0.9963
14848/15000 [============================>.] - ETA: 0s - loss: 0.0281 - acc: 0.9952
15000/15000 [==============================] - 1s 43us/step - loss: 0.0281 - acc: 0.9952 - val_loss: 0.4824 - val_acc: 0.8699
Epoch 14/20

  512/15000 [>.............................] - ETA: 0s - loss: 0.0186 - acc: 0.9980
 2048/15000 [===>..........................] - ETA: 0s - loss: 0.0183 - acc: 0.9980
 4096/15000 [=======>......................] - ETA: 0s - loss: 0.0185 - acc: 0.9978
 6144/15000 [===========>..................] - ETA: 0s - loss: 0.0188 - acc: 0.9976
 7680/15000 [==============>...............] - ETA: 0s - loss: 0.0188 - acc: 0.9978
 9728/15000 [==================>...........] - ETA: 0s - loss: 0.0219 - acc: 0.9962
11776/15000 [======================>.......] - ETA: 0s - loss: 0.0257 - acc: 0.9943
13312/15000 [=========================>....] - ETA: 0s - loss: 0.0252 - acc: 0.9944
14848/15000 [============================>.] - ETA: 0s - loss: 0.0250 - acc: 0.9948
15000/15000 [==============================] - 1s 44us/step - loss: 0.0249 - acc: 0.9949 - val_loss: 0.5048 - val_acc: 0.8699
Epoch 15/20

  512/15000 [>.............................] - ETA: 0s - loss: 0.0106 - acc: 1.0000
 2560/15000 [====>.........................] - ETA: 0s - loss: 0.0142 - acc: 0.9984
 4096/15000 [=======>......................] - ETA: 0s - loss: 0.0147 - acc: 0.9988
 5632/15000 [==========>...................] - ETA: 0s - loss: 0.0151 - acc: 0.9988
 7680/15000 [==============>...............] - ETA: 0s - loss: 0.0158 - acc: 0.9984
 9216/15000 [=================>............] - ETA: 0s - loss: 0.0167 - acc: 0.9982
11264/15000 [=====================>........] - ETA: 0s - loss: 0.0173 - acc: 0.9980
12800/15000 [========================>.....] - ETA: 0s - loss: 0.0172 - acc: 0.9982
14336/15000 [===========================>..] - ETA: 0s - loss: 0.0173 - acc: 0.9981
15000/15000 [==============================] - 1s 57us/step - loss: 0.0175 - acc: 0.9980 - val_loss: 0.5941 - val_acc: 0.8592
Epoch 16/20

  512/15000 [>.............................] - ETA: 0s - loss: 0.0280 - acc: 0.9961
 2048/15000 [===>..........................] - ETA: 0s - loss: 0.0166 - acc: 0.9976
 4096/15000 [=======>......................] - ETA: 0s - loss: 0.0144 - acc: 0.9988
 5632/15000 [==========>...................] - ETA: 0s - loss: 0.0135 - acc: 0.9991
 7168/15000 [=============>................] - ETA: 0s - loss: 0.0131 - acc: 0.9990
 9216/15000 [=================>............] - ETA: 0s - loss: 0.0133 - acc: 0.9989
10752/15000 [====================>.........] - ETA: 0s - loss: 0.0170 - acc: 0.9974
12800/15000 [========================>.....] - ETA: 0s - loss: 0.0177 - acc: 0.9970
14848/15000 [============================>.] - ETA: 0s - loss: 0.0169 - acc: 0.9973
15000/15000 [==============================] - 1s 43us/step - loss: 0.0168 - acc: 0.9973 - val_loss: 0.5711 - val_acc: 0.8694
Epoch 17/20

  512/15000 [>.............................] - ETA: 0s - loss: 0.0104 - acc: 1.0000
 2048/15000 [===>..........................] - ETA: 0s - loss: 0.0088 - acc: 1.0000
 4096/15000 [=======>......................] - ETA: 0s - loss: 0.0087 - acc: 0.9995
 6144/15000 [===========>..................] - ETA: 0s - loss: 0.0086 - acc: 0.9997
 7680/15000 [==============>...............] - ETA: 0s - loss: 0.0085 - acc: 0.9997
 9728/15000 [==================>...........] - ETA: 0s - loss: 0.0093 - acc: 0.9994
11264/15000 [=====================>........] - ETA: 0s - loss: 0.0130 - acc: 0.9983
12800/15000 [========================>.....] - ETA: 0s - loss: 0.0142 - acc: 0.9980
14848/15000 [============================>.] - ETA: 0s - loss: 0.0137 - acc: 0.9980
15000/15000 [==============================] - 1s 44us/step - loss: 0.0137 - acc: 0.9981 - val_loss: 0.6002 - val_acc: 0.8674
Epoch 18/20

  512/15000 [>.............................] - ETA: 0s - loss: 0.0083 - acc: 1.0000
 2048/15000 [===>..........................] - ETA: 0s - loss: 0.0071 - acc: 1.0000
 4096/15000 [=======>......................] - ETA: 0s - loss: 0.0069 - acc: 1.0000
 6144/15000 [===========>..................] - ETA: 0s - loss: 0.0067 - acc: 1.0000
 7680/15000 [==============>...............] - ETA: 0s - loss: 0.0066 - acc: 1.0000
 9728/15000 [==================>...........] - ETA: 0s - loss: 0.0065 - acc: 1.0000
11776/15000 [======================>.......] - ETA: 0s - loss: 0.0075 - acc: 0.9997
13824/15000 [==========================>...] - ETA: 0s - loss: 0.0095 - acc: 0.9989
15000/15000 [==============================] - 1s 41us/step - loss: 0.0095 - acc: 0.9990 - val_loss: 0.6311 - val_acc: 0.8670
Epoch 19/20

  512/15000 [>.............................] - ETA: 0s - loss: 0.0057 - acc: 1.0000
 2560/15000 [====>.........................] - ETA: 0s - loss: 0.0054 - acc: 1.0000
 4608/15000 [========>.....................] - ETA: 0s - loss: 0.0061 - acc: 0.9998
 6656/15000 [============>.................] - ETA: 0s - loss: 0.0057 - acc: 0.9998
 8704/15000 [================>.............] - ETA: 0s - loss: 0.0056 - acc: 0.9998
10752/15000 [====================>.........] - ETA: 0s - loss: 0.0062 - acc: 0.9998
12800/15000 [========================>.....] - ETA: 0s - loss: 0.0085 - acc: 0.9988
14848/15000 [============================>.] - ETA: 0s - loss: 0.0083 - acc: 0.9990
15000/15000 [==============================] - 1s 43us/step - loss: 0.0083 - acc: 0.9990 - val_loss: 0.6688 - val_acc: 0.8667
Epoch 20/20

  512/15000 [>.............................] - ETA: 0s - loss: 0.0045 - acc: 1.0000
 2048/15000 [===>..........................] - ETA: 0s - loss: 0.0044 - acc: 1.0000
 3584/15000 [======>.......................] - ETA: 0s - loss: 0.0045 - acc: 1.0000
 5632/15000 [==========>...................] - ETA: 0s - loss: 0.0042 - acc: 1.0000
 7168/15000 [=============>................] - ETA: 0s - loss: 0.0041 - acc: 1.0000
 9216/15000 [=================>............] - ETA: 0s - loss: 0.0045 - acc: 0.9999
10752/15000 [====================>.........] - ETA: 0s - loss: 0.0047 - acc: 0.9999
12288/15000 [=======================>......] - ETA: 0s - loss: 0.0052 - acc: 0.9998
14336/15000 [===========================>..] - ETA: 0s - loss: 0.0102 - acc: 0.9976
15000/15000 [==============================] - 1s 42us/step - loss: 0.0100 - acc: 0.9977 - val_loss: 0.6962 - val_acc: 0.8653

The call to fit() returns a history object. Let’s take a look at it:

str(history)
List of 2
 $ params :List of 8
  ..$ metrics           : chr [1:4] "loss" "acc" "val_loss" "val_acc"
  ..$ epochs            : int 20
  ..$ steps             : NULL
  ..$ do_validation     : logi TRUE
  ..$ samples           : int 15000
  ..$ batch_size        : int 512
  ..$ verbose           : int 1
  ..$ validation_samples: int 10000
 $ metrics:List of 4
  ..$ acc     : num [1:20] 0.783 0.904 0.929 0.943 0.954 ...
  ..$ loss    : num [1:20] 0.507 0.3 0.216 0.174 0.142 ...
  ..$ val_acc : num [1:20] 0.867 0.891 0.881 0.888 0.887 ...
  ..$ val_loss: num [1:20] 0.381 0.3 0.299 0.279 0.283 ...
 - attr(*, "class")= chr "keras_training_history"

Second model

the Second model is for four layers and The number of hidden units of the layer is 32

library(keras)
Secondmodel_4layer <- keras_model_sequential() %>% 
  layer_dense(units = 32, activation = "relu", input_shape = c(10000)) %>% 
  layer_dense(units = 32, activation = "relu") %>% 
  layer_dense(units = 32, activation = "relu") %>% 
  layer_dense(units = 1, activation = "sigmoid")

Configure the model

Validation

val_indices <- 1:10000
x_val2 <- x_train[val_indices,]
partial_x_train2 <- x_train[-val_indices,]
y_val2 <- y_train[val_indices]
partial_y_train2 <- y_train[-val_indices]

We will now train our model for 20 epochs ,batches = 512 samples,Loss function =MSE

Secondmodel_4layer %>% compile(
  optimizer = "rmsprop",
  loss = "mse",
  metrics = c("accuracy")
)
Secondmodelhistory <- Secondmodel_4layer %>% fit(
  partial_x_train,
  partial_y_train,
  epochs = 20,
  batch_size = 512,
  validation_data = list(x_val2, y_val2)
)

Comparing the two models by Plotting

compare_cx <- data.frame(
  firstmodel_3layer_train = history$metrics$loss,
  firstmodel_3layer_val = history$metrics$val_loss,
Secondmodel_4layer_train= Secondmodelhistory$metrics$loss,
Secondmodel_val = Secondmodelhistory$metrics$val_loss
) %>%
  rownames_to_column() %>%
  mutate(rowname = as.integer(rowname)) %>%
  gather(key = "type", value = "value", -rowname)
  
p <- plot_ly(compare_cx,
             x = ~rowname,
             y = ~value,
             color = ~type,
             type = "scatter",
             mode = "lines") %>% 
  layout(title = "<b>Fig 1</b> Comparing model losses",
         xaxis = list(title = "Epochs"),
         yaxis = list(title = "Loss"))
p

Results of both models on validation set :

results2 <- Secondmodel_4layer %>% evaluate(x_val2, y_val2)

   32/10000 [..............................] - ETA: 0s
 1312/10000 [==>...........................] - ETA: 0s
 2528/10000 [======>.......................] - ETA: 0s
 3968/10000 [==========>...................] - ETA: 0s
 5440/10000 [===============>..............] - ETA: 0s
 6912/10000 [===================>..........] - ETA: 0s
 8384/10000 [========================>.....] - ETA: 0s
 9856/10000 [============================>.] - ETA: 0s
10000/10000 [==============================] - 0s 36us/step
results <- firstmodel_3layer %>% evaluate(x_val, y_val)

   32/10000 [..............................] - ETA: 0s
 1792/10000 [====>.........................] - ETA: 0s
 3520/10000 [=========>....................] - ETA: 0s
 5344/10000 [===============>..............] - ETA: 0s
 7232/10000 [====================>.........] - ETA: 0s
 9120/10000 [==========================>...] - ETA: 0s
10000/10000 [==============================] - 0s 28us/step
results
$loss
[1] 0.6961613

$acc
[1] 0.8653
results2
$loss
[1] 0.1187518

$acc
[1] 0.8656

the accuracy of both models on validation set is nearly same, 86.5% and 86.6% ##Performance on test set of both models:

Secondmodel_4layer %>% fit(x_train, y_train, epochs = 20, batch_size = 512)
resultstest2 <- Secondmodel_4layer %>% evaluate(x_test, y_test)
resultstest2
firstmodel_3layer %>% fit(x_train, y_train, epochs = 20, batch_size = 512)
resultstest <- firstmodel_3layer %>% evaluate(x_test, y_test)
resultstest

The Accuracy in same for the test set is only 84.9% for first model and lower for sencond model 83.6% , this is because of overfitting of data while training , this could be taken care of with the help of regularization tecniques.Regularization is the process of modulating the quantity of information that a model is allowed to store or to add constraints on what information it’s allowed to store.

Now, we will use two techniques and Dropout

1.Regularization

Reducing networks size: The more capacity the network has, the more quickly it can model the training data, but the more susceptible it is to overfitting.Applying Weight Regularization with L2: The cost added to the loss function is proportional to the absolute value of the weight coefficients

2 layer network , units = 16 ,loss = “binary_crossentropy”

model3 <- 
  keras_model_sequential() %>%
  layer_dense(units = 16, activation = "relu", input_shape = c(10000),
              kernel_regularizer = regularizer_l2(l = 0.001)) %>%
  layer_dense(units = 16, activation = "relu",
              kernel_regularizer = regularizer_l2(l = 0.001)) %>%
  layer_dense(units = 1, activation = "sigmoid")
model3 %>% compile(
  optimizer = "rmsprop",
  loss = "binary_crossentropy",
  metrics = list("accuracy")
)
model3 %>% summary()

Validation

model3history <-model3 %>% fit(
  partial_x_train,
  partial_y_train,
  epochs = 20,
  batch_size = 512,
  validation_data = list(x_val, y_val),
  verbose = 2
)

Results :

results3 <- model3 %>% evaluate(x_val, y_val)

   32/10000 [..............................] - ETA: 0s
 1440/10000 [===>..........................] - ETA: 0s
 2816/10000 [=======>......................] - ETA: 0s
 4352/10000 [============>.................] - ETA: 0s
 5952/10000 [================>.............] - ETA: 0s
 7360/10000 [=====================>........] - ETA: 0s
 8864/10000 [=========================>....] - ETA: 0s
10000/10000 [==============================] - 0s 34us/step
results3
$loss
[1] 0.5141508

$acc
[1] 0.8657

1.1 Regularization

Applying Weight Regularization with L1: The cost added to the loss function is proportional to the absolute value of the weight coefficients

model with regularizer_l1_l2 , loss function mse, activation = softmax

2.Dropout

Dropout is one of the most effective and most commonly used regularization techniques for neural networks. The dropout rate is the fraction of the features that are zeroed out

dropout_model4 <- 
  keras_model_sequential() %>%
  layer_dense(units = 64, activation = "softmax", input_shape = c(10000)) %>%
  layer_dropout(0.6) %>%
  layer_dense(units = 16, activation = "softmax") %>%
  layer_dropout(0.6) %>%
  layer_dense(units = 1, activation = "sigmoid")
dropout_model4 %>% compile(
  optimizer = "adam",
  loss = "mse",
  metrics = list("accuracy")
)
dropout_model4 %>% summary()

Validation -model

dropout_history4 <- dropout_model4 %>% fit(
  partial_x_train,
  partial_y_train,
  epochs = 20,
  batch_size = 512,
  validation_data = list(x_val, y_val),
  verbose = 2
)

Results :

results4 <- dropout_model4 %>% evaluate(x_val, y_val)

   32/10000 [..............................] - ETA: 0s
  896/10000 [=>............................] - ETA: 0s
 1728/10000 [====>.........................] - ETA: 0s
 2656/10000 [======>.......................] - ETA: 0s
 3424/10000 [=========>....................] - ETA: 0s
 4352/10000 [============>.................] - ETA: 0s
 5312/10000 [==============>...............] - ETA: 0s
 6240/10000 [=================>............] - ETA: 0s
 7168/10000 [====================>.........] - ETA: 0s
 8128/10000 [=======================>......] - ETA: 0s
 9024/10000 [==========================>...] - ETA: 0s
 9920/10000 [============================>.] - ETA: 0s
10000/10000 [==============================] - 1s 57us/step
results4
$loss
[1] 0.1686238

$acc
[1] 0.8902

The accuracy on validation data is the best achieved with Dropout method Optimiser = ‘adam’ , activation = relu, acc=88.45 % and loss=0.4157 Optimiser = ‘rmsprop’ activation = relu, acc=87.4% and loss=0.6751 Optimiser = ‘adam’ , activation = Tanh, acc=87.25% and loss=0.5243 Optimiser = ‘adam’ , activation = relu, loss function = mse ,units = 32 ,acc=88.59% and loss=0.0951 Optimiser = ‘adam’ , activation = relu, loss function = mse ,units = 64 ,acc=88.59% and loss=0.0951 Optimiser = ‘adam’ , activation = softmax, loss function = mse ,units = 64 ,acc=89.02% and loss=0.1686

This last modification was most successful with highest accuracy

let’s check the model performance on test set

dropout_model4 %>% fit(x_train, y_train, epochs = 4, batch_size = 512)
Epoch 1/4

  512/25000 [..............................] - ETA: 2s - loss: 0.1880 - acc: 0.7285
 1024/25000 [>.............................] - ETA: 2s - loss: 0.1930 - acc: 0.7148
 2048/25000 [=>............................] - ETA: 2s - loss: 0.1953 - acc: 0.7075
 3072/25000 [==>...........................] - ETA: 1s - loss: 0.1953 - acc: 0.7035
 4096/25000 [===>..........................] - ETA: 1s - loss: 0.1950 - acc: 0.7046
 5120/25000 [=====>........................] - ETA: 1s - loss: 0.1949 - acc: 0.7045
 6144/25000 [======>.......................] - ETA: 1s - loss: 0.1949 - acc: 0.7074
 7168/25000 [=======>......................] - ETA: 1s - loss: 0.1950 - acc: 0.7055
 8192/25000 [========>.....................] - ETA: 1s - loss: 0.1952 - acc: 0.7051
 9216/25000 [==========>...................] - ETA: 1s - loss: 0.1960 - acc: 0.7024
10240/25000 [===========>..................] - ETA: 0s - loss: 0.1962 - acc: 0.7021
11264/25000 [============>.................] - ETA: 0s - loss: 0.1968 - acc: 0.6990
12288/25000 [=============>................] - ETA: 0s - loss: 0.1969 - acc: 0.6974
13312/25000 [==============>...............] - ETA: 0s - loss: 0.1967 - acc: 0.6983
14336/25000 [================>.............] - ETA: 0s - loss: 0.1964 - acc: 0.6989
15360/25000 [=================>............] - ETA: 0s - loss: 0.1963 - acc: 0.6997
16384/25000 [==================>...........] - ETA: 0s - loss: 0.1964 - acc: 0.6995
17408/25000 [===================>..........] - ETA: 0s - loss: 0.1964 - acc: 0.6994
18432/25000 [=====================>........] - ETA: 0s - loss: 0.1963 - acc: 0.7000
19456/25000 [======================>.......] - ETA: 0s - loss: 0.1966 - acc: 0.6984
20480/25000 [=======================>......] - ETA: 0s - loss: 0.1965 - acc: 0.6993
21504/25000 [========================>.....] - ETA: 0s - loss: 0.1967 - acc: 0.6982
22528/25000 [==========================>...] - ETA: 0s - loss: 0.1966 - acc: 0.6979
23552/25000 [===========================>..] - ETA: 0s - loss: 0.1970 - acc: 0.6965
24576/25000 [============================>.] - ETA: 0s - loss: 0.1970 - acc: 0.6973
25000/25000 [==============================] - 2s 63us/step - loss: 0.1968 - acc: 0.6976
Epoch 2/4

  512/25000 [..............................] - ETA: 1s - loss: 0.1962 - acc: 0.6855
 1536/25000 [>.............................] - ETA: 1s - loss: 0.1959 - acc: 0.7025
 2560/25000 [==>...........................] - ETA: 1s - loss: 0.1971 - acc: 0.7000
 3584/25000 [===>..........................] - ETA: 1s - loss: 0.1970 - acc: 0.6967
 4608/25000 [====>.........................] - ETA: 1s - loss: 0.1982 - acc: 0.6947
 5632/25000 [=====>........................] - ETA: 1s - loss: 0.1974 - acc: 0.6950
 6656/25000 [======>.......................] - ETA: 1s - loss: 0.1977 - acc: 0.6947
 7680/25000 [========>.....................] - ETA: 1s - loss: 0.1982 - acc: 0.6911
 8704/25000 [=========>....................] - ETA: 1s - loss: 0.1983 - acc: 0.6930
 9728/25000 [==========>...................] - ETA: 0s - loss: 0.1979 - acc: 0.6951
10752/25000 [===========>..................] - ETA: 0s - loss: 0.1972 - acc: 0.6983
11776/25000 [=============>................] - ETA: 0s - loss: 0.1973 - acc: 0.6964
12800/25000 [==============>...............] - ETA: 0s - loss: 0.1969 - acc: 0.6977
13824/25000 [===============>..............] - ETA: 0s - loss: 0.1966 - acc: 0.6970
14848/25000 [================>.............] - ETA: 0s - loss: 0.1963 - acc: 0.6966
15360/25000 [=================>............] - ETA: 0s - loss: 0.1964 - acc: 0.6965
16384/25000 [==================>...........] - ETA: 0s - loss: 0.1966 - acc: 0.6942
17408/25000 [===================>..........] - ETA: 0s - loss: 0.1960 - acc: 0.6965
18432/25000 [=====================>........] - ETA: 0s - loss: 0.1961 - acc: 0.6970
19456/25000 [======================>.......] - ETA: 0s - loss: 0.1963 - acc: 0.6968
20480/25000 [=======================>......] - ETA: 0s - loss: 0.1959 - acc: 0.6973
21504/25000 [========================>.....] - ETA: 0s - loss: 0.1959 - acc: 0.6980
22528/25000 [==========================>...] - ETA: 0s - loss: 0.1956 - acc: 0.6990
23552/25000 [===========================>..] - ETA: 0s - loss: 0.1954 - acc: 0.6999
24576/25000 [============================>.] - ETA: 0s - loss: 0.1952 - acc: 0.6999
25000/25000 [==============================] - 2s 64us/step - loss: 0.1951 - acc: 0.7002
Epoch 3/4

  512/25000 [..............................] - ETA: 1s - loss: 0.2007 - acc: 0.6699
 1536/25000 [>.............................] - ETA: 1s - loss: 0.1956 - acc: 0.6921
 2560/25000 [==>...........................] - ETA: 1s - loss: 0.1947 - acc: 0.6984
 3584/25000 [===>..........................] - ETA: 1s - loss: 0.1922 - acc: 0.7045
 4608/25000 [====>.........................] - ETA: 1s - loss: 0.1926 - acc: 0.7016
 5632/25000 [=====>........................] - ETA: 1s - loss: 0.1923 - acc: 0.7033
 6656/25000 [======>.......................] - ETA: 1s - loss: 0.1927 - acc: 0.7012
 7680/25000 [========>.....................] - ETA: 1s - loss: 0.1928 - acc: 0.7008
 8704/25000 [=========>....................] - ETA: 1s - loss: 0.1930 - acc: 0.7000
 9728/25000 [==========>...................] - ETA: 0s - loss: 0.1934 - acc: 0.6996
10752/25000 [===========>..................] - ETA: 0s - loss: 0.1934 - acc: 0.6987
11776/25000 [=============>................] - ETA: 0s - loss: 0.1931 - acc: 0.7002
12800/25000 [==============>...............] - ETA: 0s - loss: 0.1931 - acc: 0.7005
13824/25000 [===============>..............] - ETA: 0s - loss: 0.1932 - acc: 0.7000
14848/25000 [================>.............] - ETA: 0s - loss: 0.1932 - acc: 0.7012
15872/25000 [==================>...........] - ETA: 0s - loss: 0.1933 - acc: 0.7007
16896/25000 [===================>..........] - ETA: 0s - loss: 0.1932 - acc: 0.7010
17920/25000 [====================>.........] - ETA: 0s - loss: 0.1929 - acc: 0.7017
18944/25000 [=====================>........] - ETA: 0s - loss: 0.1929 - acc: 0.7019
19968/25000 [======================>.......] - ETA: 0s - loss: 0.1929 - acc: 0.7024
20992/25000 [========================>.....] - ETA: 0s - loss: 0.1926 - acc: 0.7037
22016/25000 [=========================>....] - ETA: 0s - loss: 0.1923 - acc: 0.7052
23040/25000 [==========================>...] - ETA: 0s - loss: 0.1924 - acc: 0.7049
24064/25000 [===========================>..] - ETA: 0s - loss: 0.1922 - acc: 0.7055
25000/25000 [==============================] - 2s 61us/step - loss: 0.1922 - acc: 0.7064
Epoch 4/4

  512/25000 [..............................] - ETA: 1s - loss: 0.1908 - acc: 0.7051
 1536/25000 [>.............................] - ETA: 1s - loss: 0.1930 - acc: 0.7083
 2560/25000 [==>...........................] - ETA: 1s - loss: 0.1923 - acc: 0.7082
 3584/25000 [===>..........................] - ETA: 1s - loss: 0.1906 - acc: 0.7121
 4608/25000 [====>.........................] - ETA: 1s - loss: 0.1910 - acc: 0.7092
 5632/25000 [=====>........................] - ETA: 1s - loss: 0.1912 - acc: 0.7076
 6656/25000 [======>.......................] - ETA: 1s - loss: 0.1915 - acc: 0.7057
 7680/25000 [========>.....................] - ETA: 1s - loss: 0.1917 - acc: 0.7056
 8704/25000 [=========>....................] - ETA: 1s - loss: 0.1914 - acc: 0.7051
 9728/25000 [==========>...................] - ETA: 0s - loss: 0.1911 - acc: 0.7073
10752/25000 [===========>..................] - ETA: 0s - loss: 0.1908 - acc: 0.7081
11776/25000 [=============>................] - ETA: 0s - loss: 0.1908 - acc: 0.7082
12800/25000 [==============>...............] - ETA: 1s - loss: 0.1915 - acc: 0.7063
13824/25000 [===============>..............] - ETA: 0s - loss: 0.1915 - acc: 0.7050
14848/25000 [================>.............] - ETA: 0s - loss: 0.1918 - acc: 0.7047
15872/25000 [==================>...........] - ETA: 0s - loss: 0.1915 - acc: 0.7050
16896/25000 [===================>..........] - ETA: 0s - loss: 0.1911 - acc: 0.7057
17920/25000 [====================>.........] - ETA: 0s - loss: 0.1911 - acc: 0.7060
18944/25000 [=====================>........] - ETA: 0s - loss: 0.1910 - acc: 0.7069
19968/25000 [======================>.......] - ETA: 0s - loss: 0.1907 - acc: 0.7078
20992/25000 [========================>.....] - ETA: 0s - loss: 0.1908 - acc: 0.7064
22016/25000 [=========================>....] - ETA: 0s - loss: 0.1910 - acc: 0.7063
23040/25000 [==========================>...] - ETA: 0s - loss: 0.1909 - acc: 0.7073
24064/25000 [===========================>..] - ETA: 0s - loss: 0.1909 - acc: 0.7074
25000/25000 [==============================] - 2s 73us/step - loss: 0.1912 - acc: 0.7069
results5 <- dropout_model4 %>% evaluate(x_test, y_test)

   32/25000 [..............................] - ETA: 1s
  832/25000 [..............................] - ETA: 1s
 1664/25000 [>.............................] - ETA: 1s
 2528/25000 [==>...........................] - ETA: 1s
 3424/25000 [===>..........................] - ETA: 1s
 4288/25000 [====>.........................] - ETA: 1s
 5184/25000 [=====>........................] - ETA: 1s
 5984/25000 [======>.......................] - ETA: 1s
 6848/25000 [=======>......................] - ETA: 1s
 7680/25000 [========>.....................] - ETA: 1s
 8512/25000 [=========>....................] - ETA: 0s
 9344/25000 [==========>...................] - ETA: 0s
10176/25000 [===========>..................] - ETA: 0s
11008/25000 [============>.................] - ETA: 0s
11872/25000 [=============>................] - ETA: 0s
12704/25000 [==============>...............] - ETA: 0s
13536/25000 [===============>..............] - ETA: 0s
14368/25000 [================>.............] - ETA: 0s
15232/25000 [=================>............] - ETA: 0s
16096/25000 [==================>...........] - ETA: 0s
16960/25000 [===================>..........] - ETA: 0s
17856/25000 [====================>.........] - ETA: 0s
18720/25000 [=====================>........] - ETA: 0s
19616/25000 [======================>.......] - ETA: 0s
20512/25000 [=======================>......] - ETA: 0s
21376/25000 [========================>.....] - ETA: 0s
22176/25000 [=========================>....] - ETA: 0s
23008/25000 [==========================>...] - ETA: 0s
23840/25000 [===========================>..] - ETA: 0s
24736/25000 [============================>.] - ETA: 0s
25000/25000 [==============================] - 1s 60us/step
results5
$loss
[1] 0.152684

$acc
[1] 0.8882

Comparison of Regularization and Dropout models : PLOT

compare_cx <- data.frame(
  model3_train = model3history$metrics$loss,
  model3_train_val = model3history$metrics$val_loss,
  dropout_model4_train = dropout_history4$metrics$loss,
 dropout_model4_val = dropout_history4$metrics$val_loss
) %>%
  rownames_to_column() %>%
  mutate(rowname = as.integer(rowname)) %>%
  gather(key = "type", value = "value", -rowname)
  
p2 <- plot_ly(compare_cx,
             x = ~rowname,
             y = ~value,
             color = ~type,
             type = "scatter",
             mode = "lines") %>% 
  layout(title = "<b>Fig 2</b> Comparing Regularization and dropout model losses",
         xaxis = list(title = "Epochs"),
         yaxis = list(title = "Loss"))
p2
LS0tCnRpdGxlOiAiTW9kaWZ5aW5nIElNREIgZXhhbXBsZSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldCh3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSkKYGBgCgoKSW4gdGhpcyBub3RlYm9vaywgd2Ugd29yayBvbiBhIGRhdGFzZXQgZnJvbSBJTURCIHNpdGUgdG8gY2xhc3NpZnkgbW92aWUgcmV2aWV3cyBpbnRvICJwb3NpdGl2ZSIgcmV2aWV3cyBhbmQgIm5lZ2F0aXZlIiByZXZpZXdzLCBqdXN0IGJhc2VkIG9uIHRoZSB0ZXh0IGNvbnRlbnQgb2YgdGhlIHJldmlld3MuCmBgYHtyfQpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHRpYmJsZSkKbGlicmFyeShwbG90bHkpCmBgYAoKCiMjIFRoZSBJTURCIGRhdGFzZXQKClRoZSBJTURCIGRhdGFzZXQgLCBhIHNldCBvZiA1MCwwMDAgaGlnaGx5LXBvbGFyaXplZCByZXZpZXdzIGZyb20gdGhlIEludGVybmV0IE1vdmllIERhdGFiYXNlLiBUaGV5IGFyZSBzcGxpdCBpbnRvIDI1LDAwMCByZXZpZXdzIGZvciB0cmFpbmluZyBhbmQgMjUsMDAwIHJldmlld3MgZm9yIHRlc3RpbmcsIGVhY2ggc2V0IGNvbnNpc3RpbmcgaW4gNTAlIG5lZ2F0aXZlIGFuZCA1MCUgcG9zaXRpdmUgcmV2aWV3cy4KVGhlIElNREIgZGF0YXNldCBjb21lcyBwYWNrYWdlZCB3aXRoIEtlcmFzLiBJdCBoYXMgYWxyZWFkeSBiZWVuIHByZXByb2Nlc3NlZDogdGhlIHJldmlld3MgKHNlcXVlbmNlcyBvZiB3b3JkcykgaGF2ZSBiZWVuIHR1cm5lZCBpbnRvIHNlcXVlbmNlcyBvZiBpbnRlZ2Vycywgd2hlcmUgZWFjaCBpbnRlZ2VyIHN0YW5kcyBmb3IgYSBzcGVjaWZpYyB3b3JkIGluIGEgZGljdGlvbmFyeS4KCiMjTG9hZGluZyB0aGUgZGF0YXNldAoKCmBgYHtyfQpsaWJyYXJ5KGtlcmFzKQppbWRiIDwtIGRhdGFzZXRfaW1kYihudW1fd29yZHMgPSAxMDAwMCkKYyhjKHRyYWluX2RhdGEsIHRyYWluX2xhYmVscyksIGModGVzdF9kYXRhLCB0ZXN0X2xhYmVscykpICU8LSUgaW1kYgpgYGAKCgpUaGUgYXJndW1lbnQgYG51bV93b3JkcyA9IDEwMDAwYCBtZWFucyB0aGF0IHdlIHdpbGwgb25seSBrZWVwIHRoZSB0b3AgMTAsMDAwIG1vc3QgZnJlcXVlbnRseSBvY2N1cnJpbmcgd29yZHMgaW4gdGhlIHRyYWluaW5nIGRhdGEuIFJhcmUgd29yZHMgd2lsbCBiZSBkaXNjYXJkZWQuIFRoaXMgYWxsb3dzIHVzIHRvIHdvcmsgd2l0aCB2ZWN0b3IgZGF0YSBvZiBtYW5hZ2VhYmxlIHNpemUuCgpUaGUgdmFyaWFibGVzIGB0cmFpbl9kYXRhYCBhbmQgYHRlc3RfZGF0YWAgYXJlIGxpc3RzIG9mIHJldmlld3MsIGVhY2ggcmV2aWV3IGJlaW5nIGEgbGlzdCBvZiB3b3JkIGluZGljZXMgKGVuY29kaW5nIGEgc2VxdWVuY2Ugb2Ygd29yZHMpLiBgdHJhaW5fbGFiZWxzYCBhbmQgYHRlc3RfbGFiZWxzYCBhcmUgbGlzdHMgb2YgMHMgYW5kIDFzLCB3aGVyZSAwIHN0YW5kcyBmb3IgIm5lZ2F0aXZlIiBhbmQgMSBzdGFuZHMgZm9yICJwb3NpdGl2ZSI6CmBgYHtyfQp0cmFpbl9sYWJlbHNbWzFdXQpgYGAKCgpUb3AgMTAsMDAwIG1vc3QgZnJlcXVlbnQgd29yZHMgYXJlIGNvbnNpZGVyZWQgLCBubyB3b3JkIGluZGV4IHdpbGwgZXhjZWVkIDEwLDAwMDoKYGBge3J9Cm1heChzYXBwbHkodHJhaW5fZGF0YSwgbWF4KSkKYGBgCgoKIyMgIERhdGEgUHJlcGFyYXRpb24KKiBPbmUtaG90LWVuY29kZSBtZXRob2QgaXMgdXNlZCBoZXJlIHNvIHRoYXQgdGhlIGxpc3RzIGFyZSBjb252ZXJ0ZWQgdG8gdmVjdG9ycyBvZiAwcyBhbmQgMXMuCkZvciBlZzpUaGlzIHdvdWxkIHR1cm4gdGhlIHNlcXVlbmNlIGBbMywgNV1gIGludG8gYSAxMCwwMDAtZGltZW5zaW9uYWwgdmVjdG9yIHRoYXQgd291bGQgYmUgYWxsIHplcm9zIGV4Y2VwdCBmb3IgaW5kaWNlcyAzIGFuZCA1LCB3aGljaCB3b3VsZCBiZSBvbmVzLiBUaGlzIHdvdWxkIGFsbG93eSB0aGUgZmlyc3QgbGF5ZXIgaW4geW91ciBuZXR3b3JrIHRvIGJlIGEgZGVuc2UgbGF5ZXIsIGNhcGFibGUgb2YgaGFuZGxpbmcgZmxvYXRpbmctcG9pbnQgdmVjdG9yIGRhdGEuCip2ZWN0b3JpemUgdGhlIGxhYmVscwoKYGBge3J9CnZlY3Rvcml6ZV9zZXF1ZW5jZXMgPC0gZnVuY3Rpb24oc2VxdWVuY2VzLCBkaW1lbnNpb24gPSAxMDAwMCkgewogICMgQ3JlYXRpbmcgYWxsLXplcm8gbWF0cml4IG9mIHNoYXBlIChsZW4oc2VxdWVuY2VzKSwgZGltZW5zaW9uKQogIHJlc3VsdHMgPC0gbWF0cml4KDAsIG5yb3cgPSBsZW5ndGgoc2VxdWVuY2VzKSwgbmNvbCA9IGRpbWVuc2lvbikKICBmb3IgKGkgaW4gMTpsZW5ndGgoc2VxdWVuY2VzKSkKICAgICMgU2V0dGluZyBzcGVjaWZpYyBpbmRpY2VzIG9mIHJlc3VsdHNbaV0gdG8gMXMKICAgIHJlc3VsdHNbaSwgc2VxdWVuY2VzW1tpXV1dIDwtIDEKICByZXN1bHRzCn0KIyB2ZWN0b3JpemUgdHJhaW5pbmcgZGF0YQp4X3RyYWluIDwtIHZlY3Rvcml6ZV9zZXF1ZW5jZXModHJhaW5fZGF0YSkKIyB2ZWN0b3JpemUgdGVzdCBkYXRhCnhfdGVzdCA8LSB2ZWN0b3JpemVfc2VxdWVuY2VzKHRlc3RfZGF0YSkKI3ZlY3Rvcml6ZSBsYWJlbHMKeV90cmFpbiA8LSBhcy5udW1lcmljKHRyYWluX2xhYmVscykKeV90ZXN0IDwtIGFzLm51bWVyaWModGVzdF9sYWJlbHMpCmBgYAoKRGF0YSB0eXBlIG9mIHNhbXBsZSBpcyBub3cgY2hhbmdlZCB0byBudW1lcmljIC4KYGBge3J9CnN0cih4X3RyYWluWzEsXSkKYGBgCgoKIyMgQnVpbGRpbmcgdGhlIE5ldXJhbCBuZXR3b3JrClRoZSBjaG9pY2Ugb2YgbmV0d29yayBmb3IgdGhlIGZpcnN0IG1vZGVsIG9mIHRocmVlIGxheWVycyBpcyB0aGUgJ3JlbHUnIGFjdGl2YXRpb24gZnVuY3Rpb24gCiBgbGF5ZXJfZGVuc2UodW5pdHMgPSAxNiwgYWN0aXZhdGlvbiA9ICJyZWx1IilgLgpFYWNoIGRlbnNlIGxheWVyIHdpdGggYSBgcmVsdWAgYWN0aXZhdGlvbiBpbXBsZW1lbnRzIHRoZSBmb2xsb3dpbmcgY2hhaW4gb2YgdGVuc29yIG9wZXJhdGlvbnM6CmBvdXRwdXQgPSByZWx1KGRvdChXLCBpbnB1dCkgKyBiKWAKCkhhdmluZyAxNiBoaWRkZW4gdW5pdHMgbWVhbnMgdGhhdCB0aGUgd2VpZ2h0IG1hdHJpeCBgV2Agd2lsbCBoYXZlIHNoYXBlIGAoaW5wdXRfZGltZW5zaW9uLCAxNilgLCBpLmUuIHRoZSBkb3QgcHJvZHVjdCB3aXRoIGBXYCB3aWxsIHByb2plY3QgdGhlIGlucHV0IGRhdGEgb250byBhIDE2LWRpbWVuc2lvbmFsIHJlcHJlc2VudGF0aW9uIHNwYWNlIChhbmQgdGhlbiB3ZSB3b3VsZCBhZGQgdGhlIGJpYXMgdmVjdG9yIGBiYCBhbmQgYXBwbHkgdGhlIGByZWx1YCBvcGVyYXRpb24pLiAKYGBge3J9CmxpYnJhcnkoa2VyYXMpCmZpcnN0bW9kZWxfM2xheWVyIDwtIGtlcmFzX21vZGVsX3NlcXVlbnRpYWwoKSAlPiUgCiAgbGF5ZXJfZGVuc2UodW5pdHMgPSAxNiwgYWN0aXZhdGlvbiA9ICJyZWx1IiwgaW5wdXRfc2hhcGUgPSBjKDEwMDAwKSkgJT4lIAogIGxheWVyX2RlbnNlKHVuaXRzID0gMTYsIGFjdGl2YXRpb24gPSAicmVsdSIpICU+JSAKICBsYXllcl9kZW5zZSh1bml0cyA9IDEsIGFjdGl2YXRpb24gPSAic2lnbW9pZCIpCmBgYAoKCiMjQ29uZmlndXJlIHRoZSBtb2RlbCAtIG9wdGltaXNlciBzZWxlY3Rpb24KTGFzdGx5LCB3ZSBuZWVkIHRvIHBpY2sgYSBsb3NzIGZ1bmN0aW9uIGFuZCBhbiBvcHRpbWl6ZXIuIGNyb3NzZW50cm9weSBpcyB1c3VhbGx5IHRoZSBiZXN0IGNob2ljZSB3aGVuIHlvdSBhcmUgZGVhbGluZyB3aXRoIG1vZGVscyB0aGF0IG91dHB1dCBwcm9iYWJpbGl0aWVzIGFuZCBmb3IgYmluYXJ5IGNsYXNzaWZpY2F0aW9uIHByb2JlbXMuIENyb3NzZW50cm9weSBpcyBhIHF1YW50aXR5IGZyb20gdGhlIGZpZWxkIG9mIEluZm9ybWF0aW9uIFRoZW9yeSwgdGhhdCBtZWFzdXJlcyB0aGUgImRpc3RhbmNlIiBiZXR3ZWVuIHByb2JhYmlsaXR5IGRpc3RyaWJ1dGlvbnMsIG9yIGluIG91ciBjYXNlLCBiZXR3ZWVuIHRoZSBncm91bmQtdHJ1dGggZGlzdHJpYnV0aW9uIGFuZCBvdXIgcHJlZGljdGlvbnMuCgpjb25maWd1cmluZyBvdXIgbW9kZWwgd2l0aCB0aGUgYHJtc3Byb3BgIG9wdGltaXplciBhbmQgdGhlIGBiaW5hcnlfY3Jvc3NlbnRyb3B5YCBsb3NzIGZ1bmN0aW9uLiAKYGBge3J9CmZpcnN0bW9kZWxfM2xheWVyICU+JSBjb21waWxlKAogIG9wdGltaXplciA9ICJybXNwcm9wIiwKICBsb3NzID0gImJpbmFyeV9jcm9zc2VudHJvcHkiLAogIG1ldHJpY3MgPSBjKCJhY2N1cmFjeSIpCikKYGBgCgoKIyMgVmFsaWRhdGluZyBvdXIgYXBwcm9hY2gKCkluIG9yZGVyIHRvIG1vbml0b3IgZHVyaW5nIHRyYWluaW5nIHRoZSBhY2N1cmFjeSBvZiB0aGUgbW9kZWwgb24gZGF0YSB0aGF0IGl0IGhhcyBuZXZlciBzZWVuIGJlZm9yZSwgd2Ugd2lsbCBjcmVhdGUgYSAidmFsaWRhdGlvbiBzZXQiIGJ5IHNldHRpbmcgYXBhcnQgMTAsMDAwIHNhbXBsZXMgZnJvbSB0aGUgb3JpZ2luYWwgdHJhaW5pbmcgZGF0YToKCmBgYHtyfQp2YWxfaW5kaWNlcyA8LSAxOjEwMDAwCgp4X3ZhbCA8LSB4X3RyYWluW3ZhbF9pbmRpY2VzLF0KcGFydGlhbF94X3RyYWluIDwtIHhfdHJhaW5bLXZhbF9pbmRpY2VzLF0KCnlfdmFsIDwtIHlfdHJhaW5bdmFsX2luZGljZXNdCnBhcnRpYWxfeV90cmFpbiA8LSB5X3RyYWluWy12YWxfaW5kaWNlc10KYGBgCgpUcmFpbmluZyBvdXIgbW9kZWwgZm9yIDIwIGVwb2NocyAoMjAgaXRlcmF0aW9ucyBvdmVyIGFsbCBzYW1wbGVzIGluIHRoZSBgeF90cmFpbmAgYW5kIGB5X3RyYWluYCB0ZW5zb3JzKSwgaW4gbWluaS1iYXRjaGVzIG9mIDUxMiBzYW1wbGVzLiBBdCB0aGlzIHNhbWUgdGltZSB3ZSB3aWxsIG1vbml0b3IgbG9zcyBhbmQgYWNjdXJhY3kgb24gdGhlIDEwLDAwMCBzYW1wbGVzIHRoYXQgd2Ugc2V0IGFwYXJ0LiBUaGlzIGlzIGRvbmUgYnkgcGFzc2luZyB0aGUgdmFsaWRhdGlvbiBkYXRhIGFzIHRoZSBgdmFsaWRhdGlvbl9kYXRhYCBhcmd1bWVudDoKYGBge3J9CmZpcnN0bW9kZWxfM2xheWVyICU+JSBjb21waWxlKAogIG9wdGltaXplciA9ICJybXNwcm9wIiwKICBsb3NzID0gImJpbmFyeV9jcm9zc2VudHJvcHkiLAogIG1ldHJpY3MgPSBjKCJhY2N1cmFjeSIpCikKCmhpc3RvcnkgPC0gZmlyc3Rtb2RlbF8zbGF5ZXIgJT4lIGZpdCgKICBwYXJ0aWFsX3hfdHJhaW4sCiAgcGFydGlhbF95X3RyYWluLAogIGVwb2NocyA9IDIwLAogIGJhdGNoX3NpemUgPSA1MTIsCiAgdmFsaWRhdGlvbl9kYXRhID0gbGlzdCh4X3ZhbCwgeV92YWwpCikKCmBgYApUaGUgY2FsbCB0byBgZml0KClgIHJldHVybnMgYSBgaGlzdG9yeWAgb2JqZWN0LiBMZXQncyB0YWtlIGEgbG9vayBhdCBpdDoKYGBge3J9CnN0cihoaXN0b3J5KQpgYGAKCiNTZWNvbmQgbW9kZWwgCnRoZSBTZWNvbmQgbW9kZWwgaXMgZm9yIGZvdXIgbGF5ZXJzIGFuZCBUaGUgbnVtYmVyIG9mIGhpZGRlbiB1bml0cyBvZiB0aGUgbGF5ZXIgaXMgMzIKYGBge3J9CmxpYnJhcnkoa2VyYXMpClNlY29uZG1vZGVsXzRsYXllciA8LSBrZXJhc19tb2RlbF9zZXF1ZW50aWFsKCkgJT4lIAogIGxheWVyX2RlbnNlKHVuaXRzID0gMzIsIGFjdGl2YXRpb24gPSAicmVsdSIsIGlucHV0X3NoYXBlID0gYygxMDAwMCkpICU+JSAKICBsYXllcl9kZW5zZSh1bml0cyA9IDMyLCBhY3RpdmF0aW9uID0gInJlbHUiKSAlPiUgCiAgbGF5ZXJfZGVuc2UodW5pdHMgPSAzMiwgYWN0aXZhdGlvbiA9ICJyZWx1IikgJT4lIAogIGxheWVyX2RlbnNlKHVuaXRzID0gMSwgYWN0aXZhdGlvbiA9ICJzaWdtb2lkIikKYGBgCgojIyNDb25maWd1cmUgdGhlIG1vZGVsIAogCiMjIFZhbGlkYXRpb24KYGBge3J9CnZhbF9pbmRpY2VzIDwtIDE6MTAwMDAKCnhfdmFsMiA8LSB4X3RyYWluW3ZhbF9pbmRpY2VzLF0KcGFydGlhbF94X3RyYWluMiA8LSB4X3RyYWluWy12YWxfaW5kaWNlcyxdCgp5X3ZhbDIgPC0geV90cmFpblt2YWxfaW5kaWNlc10KcGFydGlhbF95X3RyYWluMiA8LSB5X3RyYWluWy12YWxfaW5kaWNlc10KYGBgCgpXZSB3aWxsIG5vdyB0cmFpbiBvdXIgbW9kZWwgZm9yIDIwIGVwb2NocyAsYmF0Y2hlcyA9IDUxMiBzYW1wbGVzLExvc3MgZnVuY3Rpb24gPU1TRQoKYGBge3IsIGVjaG89VFJVRSwgcmVzdWx0cz0naGlkZSd9ClNlY29uZG1vZGVsXzRsYXllciAlPiUgY29tcGlsZSgKICBvcHRpbWl6ZXIgPSAicm1zcHJvcCIsCiAgbG9zcyA9ICJtc2UiLAogIG1ldHJpY3MgPSBjKCJhY2N1cmFjeSIpCikKClNlY29uZG1vZGVsaGlzdG9yeSA8LSBTZWNvbmRtb2RlbF80bGF5ZXIgJT4lIGZpdCgKICBwYXJ0aWFsX3hfdHJhaW4sCiAgcGFydGlhbF95X3RyYWluLAogIGVwb2NocyA9IDIwLAogIGJhdGNoX3NpemUgPSA1MTIsCiAgdmFsaWRhdGlvbl9kYXRhID0gbGlzdCh4X3ZhbDIsIHlfdmFsMikKKQpgYGAKIyNDb21wYXJpbmcgdGhlIHR3byBtb2RlbHMgYnkgUGxvdHRpbmcgCgpgYGB7cn0KY29tcGFyZV9jeCA8LSBkYXRhLmZyYW1lKAogIGZpcnN0bW9kZWxfM2xheWVyX3RyYWluID0gaGlzdG9yeSRtZXRyaWNzJGxvc3MsCiAgZmlyc3Rtb2RlbF8zbGF5ZXJfdmFsID0gaGlzdG9yeSRtZXRyaWNzJHZhbF9sb3NzLApTZWNvbmRtb2RlbF80bGF5ZXJfdHJhaW49IFNlY29uZG1vZGVsaGlzdG9yeSRtZXRyaWNzJGxvc3MsClNlY29uZG1vZGVsX3ZhbCA9IFNlY29uZG1vZGVsaGlzdG9yeSRtZXRyaWNzJHZhbF9sb3NzCikgJT4lCiAgcm93bmFtZXNfdG9fY29sdW1uKCkgJT4lCiAgbXV0YXRlKHJvd25hbWUgPSBhcy5pbnRlZ2VyKHJvd25hbWUpKSAlPiUKICBnYXRoZXIoa2V5ID0gInR5cGUiLCB2YWx1ZSA9ICJ2YWx1ZSIsIC1yb3duYW1lKQogIApwIDwtIHBsb3RfbHkoY29tcGFyZV9jeCwKICAgICAgICAgICAgIHggPSB+cm93bmFtZSwKICAgICAgICAgICAgIHkgPSB+dmFsdWUsCiAgICAgICAgICAgICBjb2xvciA9IH50eXBlLAogICAgICAgICAgICAgdHlwZSA9ICJzY2F0dGVyIiwKICAgICAgICAgICAgIG1vZGUgPSAibGluZXMiKSAlPiUgCiAgbGF5b3V0KHRpdGxlID0gIjxiPkZpZyAxPC9iPiBDb21wYXJpbmcgbW9kZWwgbG9zc2VzIiwKICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIkVwb2NocyIpLAogICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiTG9zcyIpKQpwCmBgYAojUmVzdWx0cyBvZiBib3RoIG1vZGVscyBvbiB2YWxpZGF0aW9uIHNldCA6CmBgYHtyfQpyZXN1bHRzMiA8LSBTZWNvbmRtb2RlbF80bGF5ZXIgJT4lIGV2YWx1YXRlKHhfdmFsMiwgeV92YWwyKQpyZXN1bHRzIDwtIGZpcnN0bW9kZWxfM2xheWVyICU+JSBldmFsdWF0ZSh4X3ZhbCwgeV92YWwpCnJlc3VsdHMKcmVzdWx0czIKCmBgYAoKdGhlIGFjY3VyYWN5IG9mIGJvdGggbW9kZWxzIG9uIHZhbGlkYXRpb24gc2V0IGlzIG5lYXJseSBzYW1lLCA4Ni41JSBhbmQgODYuNiUgCiMjUGVyZm9ybWFuY2Ugb24gdGVzdCBzZXQgb2YgYm90aCBtb2RlbHM6CmBgYHtyLCBlY2hvPVRSVUUsIHJlc3VsdHM9J2hpZGUnfQpTZWNvbmRtb2RlbF80bGF5ZXIgJT4lIGZpdCh4X3RyYWluLCB5X3RyYWluLCBlcG9jaHMgPSAyMCwgYmF0Y2hfc2l6ZSA9IDUxMikKcmVzdWx0c3Rlc3QyIDwtIFNlY29uZG1vZGVsXzRsYXllciAlPiUgZXZhbHVhdGUoeF90ZXN0LCB5X3Rlc3QpCnJlc3VsdHN0ZXN0MgpmaXJzdG1vZGVsXzNsYXllciAlPiUgZml0KHhfdHJhaW4sIHlfdHJhaW4sIGVwb2NocyA9IDIwLCBiYXRjaF9zaXplID0gNTEyKQpyZXN1bHRzdGVzdCA8LSBmaXJzdG1vZGVsXzNsYXllciAlPiUgZXZhbHVhdGUoeF90ZXN0LCB5X3Rlc3QpCnJlc3VsdHN0ZXN0CgpgYGAKVGhlIEFjY3VyYWN5IGluIHNhbWUgZm9yIHRoZSB0ZXN0IHNldCBpcyBvbmx5IDg0LjklIGZvciBmaXJzdCBtb2RlbCBhbmQgbG93ZXIgZm9yIHNlbmNvbmQgbW9kZWwgODMuNiUgLCB0aGlzIGlzIGJlY2F1c2Ugb2Ygb3ZlcmZpdHRpbmcgb2YgZGF0YSB3aGlsZSB0cmFpbmluZyAsCnRoaXMgY291bGQgYmUgdGFrZW4gY2FyZSBvZiB3aXRoIHRoZSBoZWxwIG9mIHJlZ3VsYXJpemF0aW9uIHRlY25pcXVlcy5SZWd1bGFyaXphdGlvbiBpcyB0aGUgcHJvY2VzcyBvZiBtb2R1bGF0aW5nIHRoZSBxdWFudGl0eSBvZiBpbmZvcm1hdGlvbiB0aGF0IGEgbW9kZWwgaXMgYWxsb3dlZCB0byBzdG9yZSBvciB0byBhZGQgY29uc3RyYWludHMgb24gd2hhdCBpbmZvcm1hdGlvbiBpdOKAmXMgYWxsb3dlZCB0byBzdG9yZS4gCgpOb3csIHdlIHdpbGwgdXNlIHR3byB0ZWNobmlxdWVzICBhbmQgRHJvcG91dAoKIyMxLlJlZ3VsYXJpemF0aW9uIApSZWR1Y2luZyBuZXR3b3JrcyBzaXplOiBUaGUgbW9yZSBjYXBhY2l0eSB0aGUgbmV0d29yayBoYXMsIHRoZSBtb3JlIHF1aWNrbHkgaXQgY2FuIG1vZGVsIHRoZSB0cmFpbmluZyBkYXRhLCBidXQgdGhlIG1vcmUgc3VzY2VwdGlibGUgaXQgaXMgdG8gb3ZlcmZpdHRpbmcuQXBwbHlpbmcgV2VpZ2h0IFJlZ3VsYXJpemF0aW9uIHdpdGggTDI6IFRoZSBjb3N0IGFkZGVkIHRvIHRoZSBsb3NzIGZ1bmN0aW9uICBpcyBwcm9wb3J0aW9uYWwgdG8gdGhlIGFic29sdXRlIHZhbHVlIG9mIHRoZSB3ZWlnaHQgY29lZmZpY2llbnRzCgoyIGxheWVyIG5ldHdvcmsgLCB1bml0cyA9IDE2ICxsb3NzID0gImJpbmFyeV9jcm9zc2VudHJvcHkiCgpgYGB7ciwgZWNobz1UUlVFLCByZXN1bHRzPSdoaWRlJ30KbW9kZWwzIDwtIAogIGtlcmFzX21vZGVsX3NlcXVlbnRpYWwoKSAlPiUKICBsYXllcl9kZW5zZSh1bml0cyA9IDE2LCBhY3RpdmF0aW9uID0gInJlbHUiLCBpbnB1dF9zaGFwZSA9IGMoMTAwMDApLAogICAgICAgICAgICAgIGtlcm5lbF9yZWd1bGFyaXplciA9IHJlZ3VsYXJpemVyX2wyKGwgPSAwLjAwMSkpICU+JQogIGxheWVyX2RlbnNlKHVuaXRzID0gMTYsIGFjdGl2YXRpb24gPSAicmVsdSIsCiAgICAgICAgICAgICAga2VybmVsX3JlZ3VsYXJpemVyID0gcmVndWxhcml6ZXJfbDIobCA9IDAuMDAxKSkgJT4lCiAgbGF5ZXJfZGVuc2UodW5pdHMgPSAxLCBhY3RpdmF0aW9uID0gInNpZ21vaWQiKQoKbW9kZWwzICU+JSBjb21waWxlKAogIG9wdGltaXplciA9ICJybXNwcm9wIiwKICBsb3NzID0gImJpbmFyeV9jcm9zc2VudHJvcHkiLAogIG1ldHJpY3MgPSBsaXN0KCJhY2N1cmFjeSIpCikKCm1vZGVsMyAlPiUgc3VtbWFyeSgpCgpgYGAKCiMjVmFsaWRhdGlvbiAKYGBge3IsIGVjaG89VFJVRSwgcmVzdWx0cz0naGlkZSd9Cm1vZGVsM2hpc3RvcnkgPC1tb2RlbDMgJT4lIGZpdCgKICBwYXJ0aWFsX3hfdHJhaW4sCiAgcGFydGlhbF95X3RyYWluLAogIGVwb2NocyA9IDIwLAogIGJhdGNoX3NpemUgPSA1MTIsCiAgdmFsaWRhdGlvbl9kYXRhID0gbGlzdCh4X3ZhbCwgeV92YWwpLAogIHZlcmJvc2UgPSAyCikKCmBgYAoKI1Jlc3VsdHMgOgpgYGB7cn0KcmVzdWx0czMgPC0gbW9kZWwzICU+JSBldmFsdWF0ZSh4X3ZhbCwgeV92YWwpCnJlc3VsdHMzCmBgYAojIzEuMSBSZWd1bGFyaXphdGlvbgpBcHBseWluZyBXZWlnaHQgUmVndWxhcml6YXRpb24gd2l0aCBMMTogVGhlIGNvc3QgYWRkZWQgdG8gdGhlIGxvc3MgZnVuY3Rpb24gIGlzIHByb3BvcnRpb25hbCB0byB0aGUgYWJzb2x1dGUgdmFsdWUgb2YgdGhlIHdlaWdodCBjb2VmZmljaWVudHMKYGBge3IsIGVjaG89VFJVRSwgcmVzdWx0cz0naGlkZSd9Cm1vZGVsMy4xIDwtIAogIGtlcmFzX21vZGVsX3NlcXVlbnRpYWwoKSAlPiUKICBsYXllcl9kZW5zZSh1bml0cyA9IDE2LCBhY3RpdmF0aW9uID0gInJlbHUiLCBpbnB1dF9zaGFwZSA9IGMoMTAwMDApLAogICAgICAgICAgICAgIGtlcm5lbF9yZWd1bGFyaXplciA9IHJlZ3VsYXJpemVyX2wxKGwgPSAwLjAwMSkpICU+JQogIGxheWVyX2RlbnNlKHVuaXRzID0gMTYsIGFjdGl2YXRpb24gPSAicmVsdSIsCiAgICAgICAgICAgICAga2VybmVsX3JlZ3VsYXJpemVyID0gcmVndWxhcml6ZXJfbDEobCA9IDAuMDAxKSkgJT4lCiAgbGF5ZXJfZGVuc2UodW5pdHMgPSAxLCBhY3RpdmF0aW9uID0gInNpZ21vaWQiKQoKbW9kZWwzLjEgJT4lIGNvbXBpbGUoCiAgb3B0aW1pemVyID0gInJtc3Byb3AiLAogIGxvc3MgPSAiYmluYXJ5X2Nyb3NzZW50cm9weSIsCiAgbWV0cmljcyA9IGxpc3QoImFjY3VyYWN5IikKKQoKbW9kZWwzLjEgJT4lIHN1bW1hcnkoKQoKIyB2YWxpZGF0aW9uIAptb2RlbDMuMWhpc3RvcnkgPC1tb2RlbDMuMSAlPiUgZml0KAogIHBhcnRpYWxfeF90cmFpbiwKICBwYXJ0aWFsX3lfdHJhaW4sCiAgZXBvY2hzID0gMjAsCiAgYmF0Y2hfc2l6ZSA9IDUxMiwKICB2YWxpZGF0aW9uX2RhdGEgPSBsaXN0KHhfdmFsLCB5X3ZhbCksCiAgdmVyYm9zZSA9IDIKKQoKI1Jlc3VsdHMgb2YgdmFsaWRhdGlvbiB3aXRoIGwxCnJlc3VsdHMzLjEgPC0gbW9kZWwzLjEgJT4lIGV2YWx1YXRlKHhfdmFsLCB5X3ZhbCkKcmVzdWx0czMuMQojIHRoZSAkbG9zcyBpcyAKI1sxXSAwLjQ5OTYzODMKIyRhY2MKI1sxXSAwLjg3NTIKYGBgCgojbW9kZWwgd2l0aCByZWd1bGFyaXplcl9sMV9sMiAsIGxvc3MgZnVuY3Rpb24gbXNlLCBhY3RpdmF0aW9uID0gc29mdG1heApgYGB7ciwgZWNobz1UUlVFLCByZXN1bHRzPSdoaWRlJ30KbW9kZWwzLjIgPC0gCiAga2VyYXNfbW9kZWxfc2VxdWVudGlhbCgpICU+JQogIGxheWVyX2RlbnNlKHVuaXRzID0gMTYsIGFjdGl2YXRpb24gPSAic29mdG1heCIsIGlucHV0X3NoYXBlID0gYygxMDAwMCksCiAgICAgICAgICAgICAga2VybmVsX3JlZ3VsYXJpemVyID0gcmVndWxhcml6ZXJfbDEobCA9IDAuMDAxKSkgJT4lCiAgbGF5ZXJfZGVuc2UodW5pdHMgPSAxNiwgYWN0aXZhdGlvbiA9ICJzb2Z0bWF4IiwKICAgICAgICAgICAgICBrZXJuZWxfcmVndWxhcml6ZXIgPSByZWd1bGFyaXplcl9sMShsID0gMC4wMDEpKSAlPiUKICBsYXllcl9kZW5zZSh1bml0cyA9IDEsIGFjdGl2YXRpb24gPSAic2lnbW9pZCIpCgptb2RlbDMuMiAlPiUgY29tcGlsZSgKICBvcHRpbWl6ZXIgPSAicm1zcHJvcCIsCiAgbG9zcyA9ICJtc2UiLAogIG1ldHJpY3MgPSBsaXN0KCJhY2N1cmFjeSIpCikKbW9kZWwzLjIgJT4lIHN1bW1hcnkoKQojIHZhbGlkYXRpb24gb2YgbW9kZWwgMy4yCm1vZGVsMy4yaGlzdG9yeSA8LW1vZGVsMy4yJT4lIGZpdCgKICBwYXJ0aWFsX3hfdHJhaW4sCiAgcGFydGlhbF95X3RyYWluLAogIGVwb2NocyA9IDIwLAogIGJhdGNoX3NpemUgPSA1MTIsCiAgdmFsaWRhdGlvbl9kYXRhID0gbGlzdCh4X3ZhbCwgeV92YWwpLAogIHZlcmJvc2UgPSAyCikKCiNSZXN1bHRzIG9mIHZhbGlkYXRpb24gd2l0aCBsMQpyZXN1bHRzMy4yIDwtIG1vZGVsMy4yICU+JSBldmFsdWF0ZSh4X3ZhbCwgeV92YWwpCnJlc3VsdHMzLjIKCmBgYAoKICAKCiMjMi5Ecm9wb3V0CkRyb3BvdXQgaXMgb25lIG9mIHRoZSBtb3N0IGVmZmVjdGl2ZSBhbmQgbW9zdCBjb21tb25seSB1c2VkIHJlZ3VsYXJpemF0aW9uIHRlY2huaXF1ZXMgZm9yIG5ldXJhbCBuZXR3b3Jrcy4gClRoZSBkcm9wb3V0IHJhdGUgaXMgdGhlIGZyYWN0aW9uIG9mIHRoZSBmZWF0dXJlcyB0aGF0IGFyZSB6ZXJvZWQgb3V0CmBgYHtyICxlY2hvPVRSVUUsIHJlc3VsdHM9J2hpZGUnfQpkcm9wb3V0X21vZGVsNCA8LSAKICBrZXJhc19tb2RlbF9zZXF1ZW50aWFsKCkgJT4lCiAgbGF5ZXJfZGVuc2UodW5pdHMgPSA2NCwgYWN0aXZhdGlvbiA9ICJzb2Z0bWF4IiwgaW5wdXRfc2hhcGUgPSBjKDEwMDAwKSkgJT4lCiAgbGF5ZXJfZHJvcG91dCgwLjYpICU+JQogIGxheWVyX2RlbnNlKHVuaXRzID0gMTYsIGFjdGl2YXRpb24gPSAic29mdG1heCIpICU+JQogIGxheWVyX2Ryb3BvdXQoMC42KSAlPiUKICBsYXllcl9kZW5zZSh1bml0cyA9IDEsIGFjdGl2YXRpb24gPSAic2lnbW9pZCIpCgpkcm9wb3V0X21vZGVsNCAlPiUgY29tcGlsZSgKICBvcHRpbWl6ZXIgPSAiYWRhbSIsCiAgbG9zcyA9ICJtc2UiLAogIG1ldHJpY3MgPSBsaXN0KCJhY2N1cmFjeSIpCikKCmRyb3BvdXRfbW9kZWw0ICU+JSBzdW1tYXJ5KCkKYGBgCiMjVmFsaWRhdGlvbiAtbW9kZWwKYGBge3IsZWNobz1UUlVFLCByZXN1bHRzPSdoaWRlJ30KZHJvcG91dF9oaXN0b3J5NCA8LSBkcm9wb3V0X21vZGVsNCAlPiUgZml0KAogIHBhcnRpYWxfeF90cmFpbiwKICBwYXJ0aWFsX3lfdHJhaW4sCiAgZXBvY2hzID0gMjAsCiAgYmF0Y2hfc2l6ZSA9IDUxMiwKICB2YWxpZGF0aW9uX2RhdGEgPSBsaXN0KHhfdmFsLCB5X3ZhbCksCiAgdmVyYm9zZSA9IDIKKQoKYGBgCiNSZXN1bHRzIDoKYGBge3J9CnJlc3VsdHM0IDwtIGRyb3BvdXRfbW9kZWw0ICU+JSBldmFsdWF0ZSh4X3ZhbCwgeV92YWwpCnJlc3VsdHM0CmBgYApUaGUgYWNjdXJhY3kgb24gdmFsaWRhdGlvbiBkYXRhIGlzIHRoZSBiZXN0IGFjaGlldmVkIHdpdGggRHJvcG91dCBtZXRob2QgCipPcHRpbWlzZXIgPSAnYWRhbScgLCAgIGFjdGl2YXRpb24gPSByZWx1LCAgICBhY2M9ODguNDUgJSAgYW5kIGxvc3M9MC40MTU3CipPcHRpbWlzZXIgPSAncm1zcHJvcCcgIGFjdGl2YXRpb24gPSByZWx1LCAgICBhY2M9ODcuNCUgICAgYW5kIGxvc3M9MC42NzUxCipPcHRpbWlzZXIgPSAnYWRhbScgLCAgIGFjdGl2YXRpb24gPSBUYW5oLCAgICBhY2M9ODcuMjUlICAgYW5kIGxvc3M9MC41MjQzCipPcHRpbWlzZXIgPSAnYWRhbScgLCAgIGFjdGl2YXRpb24gPSByZWx1LCAgbG9zcyBmdW5jdGlvbiA9IG1zZSAsdW5pdHMgPSAzMiAgLGFjYz04OC41OSUgICBhbmQgbG9zcz0wLjA5NTEKKk9wdGltaXNlciA9ICdhZGFtJyAsICAgYWN0aXZhdGlvbiA9IHJlbHUsICBsb3NzIGZ1bmN0aW9uID0gbXNlICx1bml0cyA9IDY0ICAsYWNjPTg4LjU5JSAgIGFuZCBsb3NzPTAuMDk1MQoqT3B0aW1pc2VyID0gJ2FkYW0nICwgICBhY3RpdmF0aW9uID0gc29mdG1heCwgIGxvc3MgZnVuY3Rpb24gPSBtc2UgLHVuaXRzID0gNjQgICxhY2M9ODkuMDIlICAgYW5kIGxvc3M9MC4xNjg2CgoKI1RoaXMgbGFzdCBtb2RpZmljYXRpb24gd2FzIG1vc3Qgc3VjY2Vzc2Z1bCB3aXRoIGhpZ2hlc3QgYWNjdXJhY3kgCmBgYHtyfQoKYGBgCgojbGV0J3MgY2hlY2sgdGhlIG1vZGVsIHBlcmZvcm1hbmNlIG9uIHRlc3Qgc2V0IApgYGB7cn0KZHJvcG91dF9tb2RlbDQgJT4lIGZpdCh4X3RyYWluLCB5X3RyYWluLCBlcG9jaHMgPSA0LCBiYXRjaF9zaXplID0gNTEyKQpyZXN1bHRzNSA8LSBkcm9wb3V0X21vZGVsNCAlPiUgZXZhbHVhdGUoeF90ZXN0LCB5X3Rlc3QpCnJlc3VsdHM1CiNGb3IgY29uZmlndXJ0YWlvbiA6Kk9wdGltaXNlciA9ICdhZGFtJyAsICAgYWN0aXZhdGlvbiA9IHNvZnRtYXgsICBsb3NzIGZ1bmN0aW9uID0gbXNlICx1bml0cyA9IDY0ICAsYWNjPTg5LjAyJSAgIGFuZCBsb3NzPTAuMTY4NgojKiRsb3NzID0gMC4xNTI2ODQgYW5kICRhY2MgPTAuODg4MiAgaGlnaGVzdCBvbiB0ZXN0IHNldCAKYGBgCgojI0NvbXBhcmlzb24gb2YgUmVndWxhcml6YXRpb24gYW5kIERyb3BvdXQgbW9kZWxzIDogUExPVApgYGB7cn0KY29tcGFyZV9jeCA8LSBkYXRhLmZyYW1lKAogIG1vZGVsM190cmFpbiA9IG1vZGVsM2hpc3RvcnkkbWV0cmljcyRsb3NzLAogIG1vZGVsM190cmFpbl92YWwgPSBtb2RlbDNoaXN0b3J5JG1ldHJpY3MkdmFsX2xvc3MsCiAgZHJvcG91dF9tb2RlbDRfdHJhaW4gPSBkcm9wb3V0X2hpc3Rvcnk0JG1ldHJpY3MkbG9zcywKIGRyb3BvdXRfbW9kZWw0X3ZhbCA9IGRyb3BvdXRfaGlzdG9yeTQkbWV0cmljcyR2YWxfbG9zcwopICU+JQogIHJvd25hbWVzX3RvX2NvbHVtbigpICU+JQogIG11dGF0ZShyb3duYW1lID0gYXMuaW50ZWdlcihyb3duYW1lKSkgJT4lCiAgZ2F0aGVyKGtleSA9ICJ0eXBlIiwgdmFsdWUgPSAidmFsdWUiLCAtcm93bmFtZSkKICAKcDIgPC0gcGxvdF9seShjb21wYXJlX2N4LAogICAgICAgICAgICAgeCA9IH5yb3duYW1lLAogICAgICAgICAgICAgeSA9IH52YWx1ZSwKICAgICAgICAgICAgIGNvbG9yID0gfnR5cGUsCiAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIiLAogICAgICAgICAgICAgbW9kZSA9ICJsaW5lcyIpICU+JSAKICBsYXlvdXQodGl0bGUgPSAiPGI+RmlnIDI8L2I+IENvbXBhcmluZyBSZWd1bGFyaXphdGlvbiBhbmQgZHJvcG91dCBtb2RlbCBsb3NzZXMiLAogICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiRXBvY2hzIiksCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJMb3NzIikpCnAyCmBgYAoK